package com.zmm.member.controller;


import com.zmm.common.base.model.Result;
import com.zmm.common.base.model.ResultCode;
import com.zmm.common.constant.Constant;
import com.zmm.common.constant.RedisTimeOutConstant;
import com.zmm.common.enums.AccountType;
import com.zmm.common.enums.RegistryMethodEnums;
import com.zmm.common.exception.handle.BusinessException;
import com.zmm.common.pre.handle.Assert;
import com.zmm.common.redis.key.RedisKey;
import com.zmm.common.redis.key.StringKey;
import com.zmm.member.model.Customer;
import com.zmm.member.service.CustomerService;
import com.zmm.member.service.LoginService;
import com.zmm.member.service.RegistryService;
import com.zmm.member.service.SmsSendService;
import com.zmm.member.submit.vo.RegisterLoginVo;
import com.zmm.util.auth.model.Token;
import com.zmm.util.auth.registry.annotation.AuthAnonymous;
import com.zmm.util.convert.StringUtil;
import com.zmm.util.ip.IpUtil;
import com.zmm.util.verify.BindingResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author 900045
 * @description:
 * @name RegistryController
 * @date By 2021-07-26 14:51:06
 */
@Slf4j
@Controller("Registry")
@RequestMapping("/registry")
public class RegistryController extends LoginController {
	
	@Autowired
	private LoginService loginService;
	
	@Autowired
	private RegistryService registryService;
	
	@Autowired
	private CustomerService customerService;
	
	@Autowired
	private SmsSendService smsSendService;

	/**
	 * 去到添加用户的页面
	 * @author: 900045
	 * @date: 2021-08-06 11:19:33
	 * @throws 
	
	 * @return: java.lang.String
	 **/
	@RequestMapping(value = "/to/add",method = RequestMethod.GET)
	public String toAddCustomer(){
		return "add_customer";
	}

	/**
	 * 用户注册 -- 控制器
	 * @author: 900045
	 * @date: 2021-08-05 17:40:34
	 * @throws 
	 * @param registerLoginVo: 
	 * @param result: 
	 * @return: com.zmm.common.base.model.Result
	 **/
	@AuthAnonymous
	@ResponseBody
	@RequestMapping(value = "/customer/save", method = RequestMethod.POST)
	public Result registryByPhone(@Validated RegisterLoginVo registerLoginVo, BindingResult result, HttpServletRequest request) {

		// 1.表达校验
		if (result.hasErrors()){
			//  Model model
			//model.addAttribute("orders",result)
			return BindingResultUtil.paramVerify(result);
		}
		String ip = IpUtil.getIpAddress(request);
		log.info("当前请求的ip地址");
		if (StringUtil.isBlank(registerLoginVo.getPassword()) && StringUtil.isBlank(registerLoginVo.getVerifyCode())) {
			return Result.error(ResultCode.PASSWORD_VERIFY_CODE_MEANTIME_NULL_ERROR);
		}
		if (StringUtil.isNotBlank(registerLoginVo.getPassword()) && StringUtil.isNotBlank(registerLoginVo.getVerifyCode())) {
			return Result.error(ResultCode.PASSWORD_VERIFY_CODE_MEANTIME_NOT_NULL_ERROR);
		}
		// 默认是 使用密码进行注册
		RegistryMethodEnums method = RegistryMethodEnums.PASSWORD;
		if (StringUtil.isNotBlank(registerLoginVo.getVerifyCode())){
			// 验证码不为空 ===> 手机号注册
			if (!loginService.captchaSmsVerifyCode(registerLoginVo.getPhone(), registerLoginVo.getType(), registerLoginVo.getVerifyCode())) {
				return Result.error(ResultCode.USER_VERIFY_CODE_EXPIRE);
			}
			// 将注册方式改为 验证码
			method = RegistryMethodEnums.VERIFY_CODE;
		}
		
		// 验证用户是否已经存在
		Customer customerExist = customerService.findOneCustomerByPhone(registerLoginVo.getPhone());
		if (customerExist != null) {
			return Result.error(ResultCode.USER_PHONE_ALREADY_REGISTER_EXPIRE);
		}
		registerLoginVo.setIp(ip);
		Customer customer ;
		try {
			customer = registryService.registryByPhone(registerLoginVo,method);
		} catch (BusinessException e) {
			return Result.error(e.getCode(),e.getMessage());
		}
		if (null == customer) {
			return Result.error(ResultCode.REGISTER_EXPIRE);
		}
		// 注册 -->定义为 主账户
		Token token = getToken(customer, AccountType.MAIN_ACCOUNT.getCode());

		return Result.ok().setData(token);
	}


	/**
	 * 用户想要发送短信验证码 必须先请求这个接口 获得 token 然后再去请求 member/captcha 发送验证码
	 * @author: 900045
	 * @date: 2021-08-05 18:41:36
	 * @throws 
	 * @param phoneNum: 
	 * @return: com.zmm.common.base.model.Result
	 **/
	@ResponseBody
	@GetMapping(value = "/captcha/token")
	public Result getCaptchaToken(@RequestParam("phoneNum") String phoneNum){
		Assert.notEmpty(phoneNum, ResultCode.USER_PHONE_NOT_NULL_EXPIRE);
		if (!phoneNum.matches(Constant.PATTEN_REGEX_PHONE_2)) {
			return Result.error(ResultCode.USER_PHONE_ERROR_EXPIRE);
		}
		String token = UUID.randomUUID().toString();
		// 将 获取验证码的 token 存入缓存发送验证码必须携带 参数
		RedisKey redisKey = StringKey.CAPTCHA_TOKEN.setSuffix(token);
		redisUtil.set(redisKey,phoneNum, RedisTimeOutConstant.S_600, TimeUnit.SECONDS);
		// 将token 返回给前端 前端发送验证码必须携带该 参数
		// 判断手机号码是否被注册
		boolean hasCert = customerService.validatePhoneCertificate(phoneNum);
		Map<String,Object> map = new HashMap<>(2);
		map.put("token",token);
		// 类型 1用户注册 2用户登录 3:修改密码
		// login 为 false : 登录 / 为 true : 注册
		map.put("login",hasCert);
		return Result.ok().setData(map);
	}


	/**
	 * 给用户发送短信验证码
	 * @author: 900045
	 * @date: 2021-08-05 18:53:54
	 * @throws 
	 * @param request: 
	 * @param phoneNum: 
	 * @param type: 
	 * @param token: 
	 * @return: com.zmm.common.base.model.Result
	 **/
	@ResponseBody
	@GetMapping(value = "/member/captcha")
	public Result memberCaptcha(HttpServletRequest request, String phoneNum, Integer type, String token){
		// 1.参数验证
		if (StringUtil.isBlank(phoneNum)) {
			log.error("phoneNum is null");
			return Result.error(ResultCode.USER_PHONE_NOT_NULL_EXPIRE);
		}
		if (StringUtil.isBlank(token)) {
			log.error("token is null");
			return Result.error(ResultCode.USER_TOKEN_NOT_NULL_EXPIRE);
		}
		switch (type) {
			case 1:
				// 用户注册
				break;
			case 2:
				// 用户登录
				break;
			case 3:
				// 用户修改验证码
				break;
			default:
		}

		// 2.令牌验证
		RedisKey redisKey = StringKey.CAPTCHA_TOKEN.setSuffix(token);
		// 验证码令牌 必须要保证原子性 ===> 使用 lua 脚本
		// Lua 脚本 返回 0 或者 1  0: 令牌验证失败 1: 删除成功(都能删除删除比存在)
		String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
		Long result = redisUtil.execute(script,redisKey,phoneNum);
		if (result == 0){
			// 2.1令牌验证失败
			return Result.error(ResultCode.VERIFY_CODE_TOKEN_EXPIRY);
		}

		// 3.验证通过
		String ip = IpUtil.getIpAddress(request);
		smsSendService.insertVerificationSms(phoneNum, type, ip);
		return Result.ok(ResultCode.SUCCESS);
	}
}
